//-------------------------------------------------------------------
//	Copyright (c) 2012-2014 Zhirnov Andrey
//	This file is part of the "UXGEN-ES" project.
//	See copyright notice in "Engine.h".
//-------------------------------------------------------------------

#pragma once

#include "Graphics/Primitives/Vertices.h"
#include "Graphics/Primitives/Indices.h"

namespace Engine
{
namespace Primitives
{


	//
	// Rectangle
	//

	template <typename Vert>
	struct Rectangle : RectangleIndices
	{
	// types
	public:
		typedef Vert				vertex_t;
		typedef Rectangle< Vert >	Self;


	// variables
	public:
		rect	position;
		rect	texcoord;
		color4u	color;			// TODO: add parameters
	

	// methods
	public:
		Rectangle () {}

		Rectangle (const rect &pos, const rect &texc, const color4u &color) :
			position(pos), texcoord(texc), color(color)
		{}

		static uint VerticesCount ()
		{
			return 4;
		}

		void GetVertices (void *data) const
		{
			vertex_t * verts = (vertex_t *)data;

			verts[0] = vertex_t( vec2(position.left,  position.top),	vec2(texcoord.left,  texcoord.bottom),	color );
			verts[1] = vertex_t( vec2(position.left,  position.bottom),	vec2(texcoord.left,  texcoord.top),		color );
			verts[2] = vertex_t( vec2(position.right, position.top),	vec2(texcoord.right, texcoord.bottom),	color );
			verts[3] = vertex_t( vec2(position.right, position.bottom),	vec2(texcoord.right, texcoord.top),		color );
		}

		int ScissorTest (const rect &scissorRect) const
		{
			if ( position.IsInnerRect( scissorRect ) )
				return 0;	// fully visible

			if ( position.IntersectRect( scissorRect ) )
				return 1;	// crop

			return -1;	// cut
		}

		Self Crop (const rect &scissorRect) const
		{
			Self	result = *this;

			vec2 const	posToTexc = texcoord.GetSize() / position.GetSize();

			// Left
			if ( position.left < scissorRect.left ) {
				result.position.left	= scissorRect.left;
				result.texcoord.left	= texcoord.left + (scissorRect.left - position.left) * posToTexc.x;
			}

			// Bottom
			if ( position.bottom < scissorRect.bottom ) {
				result.position.bottom	= scissorRect.bottom;
				result.texcoord.top		= texcoord.top - (scissorRect.bottom - position.bottom) * posToTexc.y;
			}

			// Right
			if ( position.right > scissorRect.right ) {
				result.position.right	= scissorRect.right;
				result.texcoord.right	= texcoord.right - (position.right - scissorRect.right) * posToTexc.x;
			}

			// Top
			if ( position.top > scissorRect.top ) {
				result.position.top		= scissorRect.top;
				result.texcoord.bottom	= texcoord.bottom + (position.top - scissorRect.top) * posToTexc.y;
			}

			return result;
		}
	};

	typedef Rectangle< Vertex2D >	Rect2D;



	//
	// Parallelogram
	//

	template <typename Vert>
	struct Parallelogram : RectangleIndices
	{
	// types
	public:
		typedef Vert					vertex_t;
		typedef Parallelogram< Vert >	Self;


	// variables
	public:
		Vert	leftTop,
				leftBottom,
				rightTop,
				rightBottom;
		

	// methods
	public:
		Parallelogram () {}

		Parallelogram (const Rectangle<Vert> &r)
		{
			leftTop		= vertex_t( vec2(r.position.left,  r.position.top),		vec2(r.texcoord.left,  r.texcoord.bottom),	r.color );
			leftBottom	= vertex_t( vec2(r.position.left,  r.position.bottom),	vec2(r.texcoord.left,  r.texcoord.top),		r.color );
			rightTop	= vertex_t( vec2(r.position.right, r.position.top),		vec2(r.texcoord.right, r.texcoord.bottom),	r.color );
			rightBottom	= vertex_t( vec2(r.position.right, r.position.bottom),	vec2(r.texcoord.right, r.texcoord.top),		r.color );
		}
		

		Parallelogram (const Vert &p01, const Vert &p11,
						const Vert &p00, const Vert &p10) :
			leftTop(p01), leftBottom(p00), rightTop(p11), rightBottom(p10)
		{}


		void Rotate (const vec2 &sinCos)
		{
			struct Util {
				static void Transform (vec2 &v, const vec2 &sc) {
					const vec2	t = v;
					v.x = sc[1] * t.x - sc[0] * t.y;
					v.y = sc[0] * t.x + sc[1] * t.y;
				}
			};

			Util::Transform( leftTop.position,		sinCos );
			Util::Transform( leftBottom.position,	sinCos );
			Util::Transform( rightTop.position,		sinCos );
			Util::Transform( rightBottom.position,	sinCos );
		}


		static uint VerticesCount ()
		{
			return 4;
		}


		void GetVertices (void *data) const
		{
			MemCopy( data, this, sizeof(*this) );
		}

		
		int ScissorTest (const rect &scissorRect) const
		{
			TODO("Parallelogram - ScissorTest");
			return 0;
		}
		

		Self Crop (const rect &scissorRect) const
		{
			TODO("Parallelogram - Crop");
			return *this;
		}
	};

	typedef Parallelogram< Vertex2D >	Parallelogram2D;



	//
	// 9 Rectangles Batch
	//
	/*
	template <typename Vert>
	struct NineRectBatch : NineRectIndices
	{
	// types
	public:
		typedef Vert					vertex_t;
		typedef NineRectBatch< Vert >	Self;

		typedef static_array< rect, 9 >	texcoords_t;
		typedef Rectangle< Vert >		rect_t;


	// variables
	protected:
		rect			_position;
		texcoords_t		_texcoords;
		color4u			_color;	
		uint8			_vertCount;


	// methods
	public:
		NineRectBatch ()
		{}
		
		uint VerticesCount () const
		{
			return _vertCount;
		}

		void GetVertices (void *data) const
		{
			vertex_t *	verts = (vertex_t *) data;

			for (uint i = 0; i < VerticesCount(); ++i)
			{
				rect_t
			}
		}
		
		Self Crop (const rect &scissorRect) const
		{
			TODO("");
			return *this;
		}
	};*/


}	// Primitives
}	// Engine